home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Languguage OS 2
/
Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO
/
language
/
ici
/
ici.cpi
/
alloc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-27
|
6KB
|
266 lines
#include "fwd.h"
#include "trace.h"
/*
* alloc.c
*
* Lowest level of ICI memory allocation before going to the host malloc()
* function. Principle functions are ici_alloc() and ici_free(). Although
* these are virtually never called directly but always through the macros
* zalloc() and zfree() defined in alloc.h.
*/
#define ALLCOLLECT 0 /* Collect on every ici_alloc call. */
#define ALLALLOC 0 /* Always call ici_alloc, no caches. */
#if WHOALLOC
#undef ALLALLOC
#define ALLALLOC 1 /* WHOALLOC requires. */
#endif
#if ALLALLOC
#undef galist
#define galist(n) 0 /* List "0" is direct calls to ici_alloc. */
#endif
char *ici_fflist[3]; /* The array of fast free lists heads. */
char *ici_fftmp; /* Temporary used in zalloc() (alloc.h). */
long ici_old_mem; /* Num bytes in use after last collect. */
long ici_new_mem; /* Num bytes alloced since last collect. */
#if WHOALLOC
/*
* WHOALLOC (see comment at top of alloc.h) works by keeping a hash table
* keyed by file name and line number. Each allocation looks up its record
* in this table and the index of that record goes in the header of the block
* allocated along with the size of the alloc. The record in the hash table
* notes the total allocations made from that location. A free pulls out
* the index of the record and subtracts the size stored in the header from
* the total in the record.
*
* Thus at any time the hash table can be scanned and all source locations
* with outstanding allocations can be printed.
*/
typedef struct
{
char *w_file;
int w_line;
long w_alloced;
}
who_t;
who_t wtab[197]; /* Prime(ish) and larger than num alloc()s in source.*/
/*
* Return a pointer to the WHOALLOC record for given file and line number.
*/
static who_t *
find_who_slot(char *file, int line)
{
who_t *w;
unsigned long h;
unsigned char *p;
h = line;
for (p = (unsigned char *)file; *p != NULL; ++p)
h = (h << 3) ^ (h >> 24) ^ *p;
for
(
w = &wtab[h % nels(wtab)];
w->w_file != NULL && (w->w_line != line || strcmp(w->w_file,file) != 0);
--w
)
{
if (w == wtab)
w = &wtab[nels(wtab)];
}
return w;
}
/*
* Record this allocation against the given file and line number.
*/
static void
note_who_alloced(void *p, int size, char *file, int line)
{
who_t *w;
w = find_who_slot(file, line);
if (w->w_file == NULL)
{
w->w_file = file;
w->w_line = line;
}
w->w_alloced += size;
gahead(p)->ga_who = w - wtab;
gahead(p)->ga_size = size;
}
/*
* Reverse the record of allocation of this block.
*/
static void
note_free(void *p)
{
wtab[gahead(p)->ga_who].w_alloced -= gahead(p)->ga_size;
}
/*
* Print a table of outstanding allocation amounts by file and line number.
*/
static void
report_who_still_alloced(void)
{
who_t *w;
for (w = wtab; w < &wtab[nels(wtab)]; ++w)
{
if (w->w_alloced == 0)
continue;
fprintf(stderr, "%7d bytes from %s %d\n",
w->w_alloced,
w->w_file,
w->w_line);
}
}
#endif /*WHOALLOC*/
/*
* Free everything on our fast free lists. Done just before a regular
* garbage collection because things still on them were not used and
* this is a good predictor that they won't be used again.
*
* Done after an externally prompted collection so that as much memory
* as possible is released.
*/
static void
drop_fast_free_lists(void)
{
char *p;
int i;
for (i = 0; i < nels(ici_fflist); ++i)
{
while (ici_fflist[i] != NULL)
{
p = ici_fflist[i];
ici_fflist[i] = *(char **)p;
ici_free(p);
}
}
}
/*
* Normal collection. Triggered by having allocated as much new memory
* as we previsouly has memory tied up in objects after the previous
* garbage collect.
*/
static void
normal_reclaim(void)
{
/*
* We've allocated as much new memory as we had things to
* start with. Time to garbage collect. First we throw away
* our private lists (because we hardly ever free things outside
* garbage collection, the things on them now obviously have been
* there since the last garbage collection and they weren't needed,
* so toss 'em).
*/
drop_fast_free_lists();
collect();
}
/*
* Garbage collection triggered by other than our internal mechanmism.
* Don't do this unless you really must. It will free all memory it can
* but will reduce subsequent performance.
*/
void
ici_reclaim(void)
{
collect();
drop_fast_free_lists();
#if WHOALLOC
report_who_still_alloced();
#endif
}
void *
#if WHOALLOC
ici_alloc(int n, char *file, int line)
#else
ici_alloc(int n)
#endif
{
char *p;
#ifndef NOTRACE
if (trace_yes && (trace_flags & TRACE_MEM))
fprintf(stderr, "trace: ici_alloc %d bytes\n", n);
#endif
#if !ALLCOLLECT
if ((ici_new_mem += n) > ici_old_mem)
#endif
normal_reclaim();
switch (galist(n))
{
case 1:
if (ici_fflist[1] != NULL)
{
ici_fflist[1] = *(char **)(p = ici_fflist[1]);
return p;
}
n = LIST1Z;
break;
case 2:
if (ici_fflist[2] != NULL)
{
ici_fflist[2] = *(char **)(p = ici_fflist[2]);
return p;
}
n = LIST2Z;
break;
}
n += GALLOC_HEADZ;
if
(
(p = malloc((unsigned)n)) == NULL
&&
(
ici_new_mem == 0
||
(normal_reclaim(), (p = malloc((unsigned)n)) == NULL)
)
)
{
error = "ran out of memory";
return NULL;
}
#ifdef BUGHUNT
memset(p, rand(), n);
#endif
#ifndef SMALL
((gahead_t *)p)->ga_list = galist(n - GALLOC_HEADZ);
#endif
#if WHOALLOC
note_who_alloced(gadata(p), n, file, line);
#endif
return gadata(p);
}
void
ici_free(void *p)
{
#if WHOALLOC
note_free(p);
#endif
free((void *)gahead(p));
}